﻿#pragma once

#include "../../thirdparty/klogger/klogger/interface/logger.h"
#include "../util/box_std_allocator.hh"
#include "../util/object_pool.hh"
#include "../lang/lang.hh"
#include "../detail/sys_logger_impl.hh"

#include "box_network.hh"

#include <cstdint>
#include <ctime>
#include <iostream>
#include <list>
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>

namespace rpc {
class Transport;
class Rpc;
class RpcImpl;
class StubCall;
class Stub;
class Proxy;
class ProxyHandlerImpl;
} // namespace rpc

namespace kratos {
namespace config {
class BoxConfigImpl;
}
} // namespace kratos

namespace kratos {
namespace argument {
class BoxArgumentImpl;
class BoxArgument;
} // namespace argument
} // namespace kratos

namespace klogger {
class Logger;
class Appender;
} // namespace klogger

namespace kratos {
namespace lang {
class Lang;
class LangImpl;
} // namespace lang
} // namespace kratos

namespace kratos {
namespace console {
class ConsoleImpl;
} // namespace console
} // namespace kratos

namespace kratos {
namespace service {

class ServiceFinder;
class ServiceFinderImpl;
class ServiceRegister;
class ServiceRegisterImpl;
class BoxNetwork;
class ServiceContextImpl;
class ServiceContext;
class ServiceBox;
class RpcLoggerImpl;
class ServiceHttpLoader;
class CommandManager;
class ProcStat;
class ProcStatImpl;
class LocalCommand;
class SysLoggerImpl;
class TimerFactoryImpl;
class ServicelLayer;
class DebugServerImpl;
class InterfaceDescriptorFactoryImpl;

/**
 * \brief 服务容器.
 * 加载并运行服务，提供跨平台的运行能力，包含服务发现，服务远程调用，服务更新等功能
 */
class ServiceBox : public BoxNetwork {
private:
  using StringMap = PoolUnorederedMap<std::string, std::string>;
  using StringSet = PoolUnorderedSet<std::string>;

  std::shared_ptr<ServiceFinder>                  service_finder_     {nullptr}; ///< 服务发现
  std::shared_ptr<ServiceRegister>                service_register_   {nullptr}; ///< 服务注册
  unique_pool_ptr<config::BoxConfigImpl>          box_config_         {nullptr}; ///< 配置
  unique_pool_ptr<argument::BoxArgumentImpl>      box_argument_       {nullptr}; ///< 命令行参数
  unique_pool_ptr<ServiceHttpLoader>              http_loader_        {nullptr}; ///< 服务更新
  unique_pool_ptr<ServiceContextImpl>             service_context_    {nullptr}; ///< 暴露给用户的调用上下文
  unique_pool_ptr<RpcLoggerImpl>                  rpc_logger_         {nullptr}; ///< RPC日志
  unique_pool_ptr<lang::LangImpl>                 lang_               {nullptr}; ///< 多国语言
  unique_pool_ptr<LocalCommand>                   local_command_      {nullptr}; ///< 本地命令
  unique_pool_ptr<CommandManager>                 command_manager_    {nullptr}; ///< 命令管理器
  unique_pool_ptr<ProcStatImpl>                   proc_stat_          {nullptr}; ///< 进程信息统计
  unique_pool_ptr<SysLoggerImpl>                  sys_logger_         {nullptr}; ///< 系统日志
  unique_pool_ptr<rpc::ProxyHandlerImpl>          proxy_handler_      {nullptr}; ///< 代理处理器
  unique_pool_ptr<console::ConsoleImpl>           console_            {nullptr}; ///< 控制台
  unique_pool_ptr<ServicelLayer>                  service_layer_      {nullptr}; ///< 服务管道层
  unique_pool_ptr<TimerFactoryImpl>               rpc_timer_factory_  {nullptr}; ///< RPC定时器工厂
  unique_pool_ptr<DebugServerImpl>                debug_server_       {nullptr}; ///< 调试本地服务器
  unique_pool_ptr<InterfaceDescriptorFactoryImpl> descriptor_factory_ {nullptr}; ///< 接口描述工厂

  StringMap   registered_service_map_; ///< 已经注册的服务
  std::string config_file_path_;       ///< 配置文件路径
  bool        is_wait_stop_{false};    ///< 等待关闭标志

  klogger::Logger*   logger_          {nullptr}; ///< 日志
  klogger::Appender* console_appender_{nullptr}; ///< 容器默认日志，在用户日志建立前使用
  klogger::Appender* user_appender_   {nullptr}; ///< 用户日志

  std::shared_ptr<rpc::Transport> proxy_transport_; ///< proxy管道
  unique_pool_ptr<rpc::RpcImpl>   rpc_{nullptr};    ///< RPC实例

  StringSet installed_service_uuids_; ///< 已经安装的服务UUID

  constexpr static char const* CONSOLE_LOGGER_CONFIG_LINE =
      "console://;line=[%y%m%d-%H:%M:%S:%U];flush=true"; ///< console日志默认配置

public:
  /**
   * 构造
   */
  ServiceBox();
  /**
   * 析构
   */
  virtual ~ServiceBox();
  /**
   * 启动, 读取配置并启动所有子系统.
   *
   * \param argc 参数个数
   * \param argv 参数数组
   * \retval true 成功
   * \retval false 失败
   */
  auto start(int argc, const char **argv) -> bool;
  /**
   * 关闭.
   *
   * \return true 成功
   * \retval false 失败
   */
  auto stop() -> bool;
  /**
   * 逻辑主循环.
   *
   * \param now 当前时间戳，毫秒
   */
  auto update(std::time_t now = 0) -> void;

  /**
   * 检测是否已经安装了某个服务
   *
   * \param uuid 服务UUID
   * \return true或false
   */
  auto is_installed(const std::string& uuid) -> bool;

  /**
   * 注册服务.
   *
   * \param name 服务名
   * \return true 成功
   * \retval false 失败
   */
  auto register_service(const std::string &name) -> bool;
  /**
   * 取消服务注册.
   *
   * \param name 服务名
   * \return true或false
   */
  auto unregister_service(const std::string &name) -> bool;
  /**
   * 获取用于RPC通信的传输实例，如果没有则立即返回空实例.
   *
   * \param name 服务名
   * \return 传输实例
   */
  auto try_get_transport(const std::string &name)
      -> std::shared_ptr<rpc::Transport>;
  /**
   * 获取用于RPC通信的传输实例，在实例建立过程中将阻塞执行执行线程.
   *
   * \param name 服务名
   * \param timeout 等待时间，毫秒
   * \return 传输实例
   */
  auto get_transport_sync(const std::string &name, std::time_t timeout)
      -> std::shared_ptr<rpc::Transport>;
  /**
   * 检查是否已经停止.
   *
   * \return true或false
   */
  auto is_wait_stop() const -> bool;
  /**
   * 设置停止标志.
   *
   * \return true或false
   */
  auto set_wait_stop_flag() -> void;
  /**
   * 取得命令行参数.
   *
   * \return true或false
   */
  auto get_argument() const -> const argument::BoxArgument &;
  /**
   * 写日志.
   *
   * \param log_level 日志等级 @see klogger::Logger
   * \param log_line 日志行
   */
  auto write_log_line(int log_level, const std::string &log_line) -> void;
  /**
   * 取得配置器.
   *
   * \return 配置器
   */
  virtual auto get_config() -> kratos::config::BoxConfig & override;
  /**
   * 获取上下文.
   *
   * \return 上下文
   */
  auto get_context() -> ServiceContext *;
  /**
   * 获取命令管理器.
   *
   * \return 命令管理器
   */
  auto get_command_manager() -> CommandManager *;
  /**
   * 获取进程信息统计.
   *
   * \return 进程信息统计
   */
  auto get_proc_stat() -> ProcStat *;
  /**
   * 检测是否已daemon方式启动.
   *
   * \return
   */
  auto check_daemon() -> void;
  /**
   * 获取服务注册接口.
   *
   * \return
   */
  auto get_service_register() -> ServiceRegister *;
  /**
   * 获取本容器已经注册的服务.
   *
   * \return
   */
  auto get_register_services() -> const StringMap &;
  /**
   * 获取系统日志.
   *
   * \return 系统日志
   */
  auto get_sys_logger() -> SysLogger *;
  /**
   * 获取代理处理器.
   *
   * \return
   */
  auto get_proxy_handler() -> rpc::ProxyHandlerImpl *;
  /**
   * 获取RPC实例.
   * 
   * \return 
   */
  auto get_rpc() -> rpc::Rpc *;
  /**
   * 获取控制台实例.
   *
   * \return
   */
  auto get_console()->kratos::console::ConsoleImpl*;
  /**
   * 获取服务发现 
   */
  auto get_service_finder()->ServiceFinder*;
  /**
   * 获取ChannelLayer  
   */
  auto get_service_layer()->ServicelLayer*;
  /**
   * 获取服务更新 
   */
  auto get_service_updater()->ServiceHttpLoader*;
  /**
   * @brief 获取调试服务器
   * @return 调试服务器
  */
  auto get_debug_server()->DebugServerImpl*;

public:
  /**
   * 取得日志添加器.
   *
   * \return 日志添加器
   */
  virtual auto get_logger_appender() -> klogger::Appender * override;
  /**
   * 获取本地化实例.
   *
   * \return 本地化实例
   */
  virtual auto get_lang() -> lang::Lang * override;

protected:
  /**
   * @see BoxNetwork::on_listen.
   */
  virtual void on_listen(const std::string &name, bool success,
                         std::shared_ptr<BoxChannel> &channel) override;
  /**
   * @see BoxNetwork::on_accept.
   */
  virtual void on_accept(std::shared_ptr<BoxChannel> &channel) override;
  /**
   * @see BoxNetwork::on_connect.
   */
  virtual void on_connect(const std::string &name, bool success,
                          std::shared_ptr<BoxChannel> &channel) override;
  /**
   * @see BoxNetwork::on_close.
   */
  virtual void on_close(std::shared_ptr<BoxChannel> &channel) override;
  /**
   * @see BoxNetwork::on_data.
   */
  virtual void on_data(std::shared_ptr<BoxChannel> &channel) override;

public:
  /**
   * 写入日志.
   *
   * \param id 语言ID
   * \param level 日志等级
   * \param args 日志参数
   * \return
   */
  template <typename... ARGS>
  auto write_log(lang::LangID id, int level, ARGS... args) -> void {
    const auto &fmt = get_lang()->get_lang(id);
    if (fmt.empty()) {
      return;
    }
    if (get_logger_appender()) {
      get_logger_appender()->write(level, fmt.c_str(), args...);
    } else {
      if (sys_logger_) {
        sys_logger_->log(level, fmt.c_str(), args...);
      } else {
        std::fprintf(stderr, fmt.c_str(), args...);
      }
    }
  }

private:
  /**
   * 启动, 读取配置并启动所有子系统.
   *
   * \param argc 参数个数
   * \param argv 参数数组
   * \retval true 成功
   * \retval false 失败
   */
  auto start_internal(int argc, const char **argv) -> bool;
  /**
   * 关闭.
   * 
   * \retval true 成功
   * \retval false 失败
   */
  auto stop_unsafe() -> bool;
  /**
   * 异常安全的关闭.
   * 
   * \return true或false
   */
  auto stop_internal() -> bool;
  /**
   * 逻辑主循环.
   *
   * \param now 当前时间戳，毫秒
   */
  auto update_internal(std::time_t now) -> void;
  /**
   * 异常安全的主循环.
   *
   * \param now 当前时间戳，毫秒
   * \return
   */
  auto update_unsafe(std::time_t now) -> void;
  /**
   * 加载配置.
   *
   * \return retval true 成功
   * \retval false 失败
   */
  auto load_config() -> bool;
  /**
   * 根据用户配置,等待必要的服务注册到集群后才能继续运行.
   */
  auto wait_necessary_service() -> void;
  /**
   * 初始化服务发现.
   *
   * \return true或false
   */
  auto initialize_service_finder() -> bool;
  /**
   * 在用户日志建立前，首先建立默认终端日志组件.
   *
   * \return true或false
   */
  auto start_console_logger() -> bool;
  /**
   * 启动用户配置的标准日志组件.
   *
   * \param logger_config_line 用户日志配置
   * \retval true 成功
   * \retval false 失败
   */
  auto start_standard_logger(const std::string &logger_config_line) -> bool;
  /**
   * 加载本地服务.
   *
   * \param uuid 服务UUID
   * \param file_path 服务路径
   * \retval true 成功
   * \retval false 失败
   */
  auto load_service(const std::string uuid, const std::string &file_path)
      -> bool;
  /**
   * 加载所有本地服务.
   *
   * \param service_dir 服务所在目录
   * \retval true 成功
   * \retval false 失败
   */
  auto load_all_service(const std::string &service_dir) -> bool;
  /**
   * 销毁所有本地服务实例.
   *
   * \retval true 成功
   * \retval false 失败
   */
  auto release_all_service() -> bool;
  /**
   * 下载所有本地bundle(.so/.dll).
   * 
   * \return 
   */
  auto unload_all_bundle() -> bool;
  /**
   * 启动所有监听器
   *
   * \return true或falese
   */
  auto start_all_listener() -> bool;
  /**
   * 启动一个监听器.
   *
   * \param host 地址
   * \param name 监听器名称
   * \return true或falese
   */
  auto start_listener(const std::string &host, const std::string &name) -> bool;
  /**
   * 打印启动信息.
   */
  auto print_startup_info() -> void;
  /**
   * 执行命令行命令并退出.
   *
   * \return
   */
  auto do_command() -> void;
  /**
   * 配置器重载.
   *
   * \return
   */
  auto register_config_reload_listener() -> void;
  /**
   * 监听器变化，只支持新增.
   *
   * \param new_config 新的配置
   * \return
   */
  auto on_listener_change(const config::BoxConfig &new_config) -> void;
  /**
   * 日志配置变化.
   *
   * \param new_config 新的配置
   * \return
   */
  auto on_logger_config_line_change(const config::BoxConfig &new_config)
      -> void;
  /**
   * 检测是否是客户端.
   *
   * \return
   */
  auto is_client() -> bool;
  /**
   * 解析命令行.
   *
   * \param argc 参数个数
   * \param argv 参数数组
   * \return true或false
   */
  auto parse_command_line(int argc, const char **argv) -> bool;
  /**
   * 加载并解析配置文件.
   *
   * \return true或false
   */
  auto parse_config_file() -> bool;
  /**
   * 初始化.
   *
   * \return true或false
   */
  auto initialize() -> bool;
  /**
   * 尝试从配置中心下载配置.
   *
   * \return true或false
   */
  auto try_download_from_config_center() -> bool;
  /**
   * 关闭日志添加器.
   *
   * \return
   */
  auto close_logger_appender() -> void;
  /**
   * 开启系统日志.
   *
   * \return true或false
   */
  auto start_syslog() -> bool;
  /**
   * 启动proxy的监听器.
   *
   * \return true或false
   */
  auto start_proxy_listener() -> bool;
  /**
   * 连接到代理.
   *
   * \return true或false
   */
  auto connect_to_proxy() -> bool;
  /**
   * 随机从listener.host内选择一个地址.
   *
   * \return 监听地址
   */
  auto random_get_listener_host() -> std::string;
  /**
   * @brief 尝试启动脚本调试服务器
   * @return 
  */
  auto try_start_debugger_server() -> bool;
};

} // namespace service
} // namespace kratos
